/*
 * Media.java
 *    Author: nfk
 *      Date: Sep 26, 2008
 *      
 *   Classes:
 *      Media
 */

package at.syncme.framework.midp;


import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.VolumeControl;


/**
 * A music / sound effect utility class.
 * @author nfk
 */
public final class Media {

    private static final Random r;

    private static final String TYPE_MP3               = "audio/mpeg";
    private static final String TYPE_MIDI              = "audio/midi";

    private static boolean      supportsMP3Checked     = false;
    private static boolean      supportsMP3            = false;
    private static boolean      supportsMIDIChecked    = false;
    private static boolean      supportsMIDI           = false;

    private static Player[]     explosions;
    private static Player[]     bombs;
    private static Player[]     kills;
    private static Player[]     backgroundMusic;
    private static Player       currentBackgroundMusic = null;

    private static boolean      soundTurnedOn          = true;

    static {
        r = new Random();

        if (hasMP3Support()) {
            explosions = new Player[] {
                    createNewPlayer("/exp1.mp3", TYPE_MP3, true),
                    createNewPlayer("/exp2.mp3", TYPE_MP3, true)
            };
            
            kills = new Player[] {
                createNewPlayer("/kill1.mp3", TYPE_MP3, true),
                createNewPlayer("/kill2.mp3", TYPE_MP3, true),
                createNewPlayer("/kill3.mp3", TYPE_MP3, true),
                createNewPlayer("/kill4.mp3", TYPE_MP3, true),
                createNewPlayer("/kill5.mp3", TYPE_MP3, true)
            };
            
            bombs = new Player[] {
                    createNewPlayer("/bomb1.mp3", TYPE_MP3, true),
                    createNewPlayer("/bomb2.mp3", TYPE_MP3, true)
            };

            // backgroundMusic = new Player[4];
            // backgroundMusic[0] = createNewPlayer("/bg01.mp3", TYPE_MP3);
            // backgroundMusic[0].setLoopCount(-1);
            // backgroundMusic[1] = createNewPlayer("/bg02.mp3", TYPE_MP3);
            // backgroundMusic[1].setLoopCount(-1);
            // backgroundMusic[2] = createNewPlayer("/bg03.mp3", TYPE_MP3);
            // backgroundMusic[2].setLoopCount(-1);
            // backgroundMusic[3] = createNewPlayer("/bg04.mp3", TYPE_MP3);
            // backgroundMusic[3].setLoopCount(-1);
        }
    }
    
    /**
     * Plays any of the available explosion sounds.
     * @return if start of playing was successful
     */
    private static boolean playPrivateSound(Player[] array) {
        boolean result = false;

        if (soundTurnedOn && array != null) {
            try {
                final int choice = r.nextInt(array.length);
                final Player p = array[choice];
                p.start();
                result = true;
            } catch (final MediaException ex) {
                // Leave result at false
            }
        }

        return result;
    }


    /**
     * play an explosion sound
     * @return if start of playing was successful
     */
    public static boolean playExplosionSound() {
        return playPrivateSound(explosions);
    }
    
    /**
     * play a bomb sound
     * @return if start of playing was successful
     */
    public static boolean playBombSound() {
        return playPrivateSound(bombs);
    }
    
    /**
     * play a kill sound
     * @return if start of playing was successful
     */
    public static boolean playKillSound() {
        return playPrivateSound(kills);
    }


    /**
     * Plays any of the available background music.
     * @return if start of playing was successful
     */
    public synchronized static boolean playBackgroundMusic() {
        boolean result = false;

        if (soundTurnedOn && backgroundMusic != null) {
            if (currentBackgroundMusic != null) {
                stopBackgroundMusic();
            }

            try {
                final int choice = r.nextInt(backgroundMusic.length);
                final Player p = backgroundMusic[choice];
                p.start();
                currentBackgroundMusic = p;
                result = true;
            } catch (final MediaException ex) {
                // Leave result at false
            }
        }

        return result;
    }


    /**
     * Stops the background music if it is currently playing. If nothing plays, call is silently ignored.
     */
    public synchronized static void stopBackgroundMusic() {
        if (soundTurnedOn && currentBackgroundMusic != null) {
            try {
                currentBackgroundMusic.stop();
                currentBackgroundMusic.setMediaTime(0);
                currentBackgroundMusic = null;
            } catch (final MediaException ex) {
                // Ignore
            }
        }
    }


    /**
     * Returns if the local device supports playback of MP3 content.
     * @return MP3 support status
     */
    public static boolean hasMP3Support() {
        if (!supportsMP3Checked) {
            final String[] s = Manager.getSupportedProtocols(TYPE_MP3);
            supportsMP3Checked = true;
            supportsMP3 = (s.length != 0);
        }

        return supportsMP3;
    }


    /**
     * Returns if the local device supports playback of MIDI content.
     * @return MIDI support status
     */
    public static boolean hasMIDISupport() {
        if (!supportsMIDIChecked) {
            final String[] s = Manager.getSupportedProtocols(TYPE_MIDI);
            supportsMIDIChecked = true;
            supportsMIDI = (s.length != 0);
        }

        return supportsMIDI;
    }


    /**
     * Returns if the local device has full audio support for MomberBan (MP3 + MIDI required).
     * @return full audio support status
     */
    public static boolean hasFullAudioSupport() {
        return (hasMP3Support() && hasMIDISupport());
    }


    /**
     * Sets the volume level of the sound effects.
     * @param volume volume level; range from 1 - 100
     */
    public static void setExplosionVolume(final byte volume) {
        if (volume < 1 || volume > 100) {
            throw new IllegalArgumentException("Volume range must be within 1 - 100.");
        }

        Player p = null;
        VolumeControl c = null;
        for (int i = 0; i < explosions.length; i++) {
            p = explosions[i];
            c = (VolumeControl) p.getControl("VolumeControl");
            if (c != null) {
                c.setLevel(volume);
            }
        }
    }


    /**
     * Sets the volume level of the background music.
     * @param volume volume level; range from 1 - 100
     */
    public static void setBackgroundVolume(final byte volume) {
        if (volume < 1 || volume > 100) {
            throw new IllegalArgumentException("Volume range must be within 1 - 100.");
        }

        Player p = null;
        VolumeControl c = null;
        for (int i = 0; i < backgroundMusic.length; i++) {
            p = backgroundMusic[i];
            c = (VolumeControl) p.getControl("VolumeControl");
            if (c != null) {
                c.setLevel(volume);
            }
        }
    }


    /**
     * Mutes all game sounds (music + effects).
     */
    public static void mute() {
        mute(true);
    }


    /**
     * Unmutes all game sounds (music + effects).
     */
    public static void unmute() {
        mute(false);
    }


    /** Helper method to mute / unmute. */
    private static void mute(final boolean status) {
        VolumeControl c = null;
        Player p = null;
        int i;

        for (i = 0; i < backgroundMusic.length; i++) {
            p = backgroundMusic[i];
            c = (VolumeControl) p.getControl("VolumeControl");
            if (c != null) {
                c.setMute(status);
            }
        }

        for (i = 0; i < explosions.length; i++) {
            p = explosions[i];
            c = (VolumeControl) p.getControl("VolumeControl");
            if (c != null) {
                c.setMute(status);
            }
        }
    }


    /**
     * Turns on sound engine (play..() methods do their job).
     */
    public static void turnSoundOn() {
        soundTurnedOn = true;
    }


    /**
     * Turns off sound engine (play..() method calls are silently ignored).
     */
    public static void turnSoundOff() {
        soundTurnedOn = false;
    }


    /** Helper method to create a Player instance for given path to file. */
    private static Player createNewPlayer(final String filePath, final String contentType,
            final boolean prefetch) {
        Player result = null;

        final InputStream is = Media.class.getResourceAsStream(filePath);
        try {
            result = Manager.createPlayer(is, contentType);
            if (prefetch) {
                result.prefetch();
            }
        } catch (final MediaException ex) {
            // Leave result at null
        } catch (final IOException ex) {
            // Leave result at null
        }

        return result;
    }


    /** Forbid construction. */
    private Media() {
        throw new Error();
    }

}

/* End of Media.java */
